Completed
Push — master ( ca1024...3a4b73 )
by Andres
47s
created

generate_decay.js ➔ getAtomBreakdown   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
c 1
b 0
f 0
nc 1
dl 0
loc 10
rs 9.4285
nop 1
1
/* eslint-env node */
2
/*jslint node: true */
3
'use strict';
4
5
let jsonfile = require('jsonfile');
6
7
let args = process.argv.slice(2);
8
9
let resources = jsonfile.readFileSync(args[0] + '/data/resources.json');
10
let elements = jsonfile.readFileSync(args[0] + '/data/elements.json');
11
12
let isotopeMatrix = {};
13
14
function getAtomBreakdown(isotope) {
15
  let element = isotope.replace(/^[0-9]*/, '');
16
  let number = parseInt(isotope.replace(element, ''));
17
  let elementNumber = elements[element].number;
18
  let neutronNumber = number - elementNumber;
19
  return {
20
    atom: elementNumber,
21
    n: neutronNumber
22
  };
23
}
24
25
for (let element in elements) {
26
  for (let isotope in elements[element].isotopes) {
27
    let breakdown = getAtomBreakdown(isotope);
28
    if (!isotopeMatrix[breakdown.atom]) {
29
      isotopeMatrix[breakdown.atom] = {};
30
    }
31
    isotopeMatrix[breakdown.atom][breakdown.n] = isotope;
32
  }
33
}
34
35
for (let element in elements) {
36
  for (let key in elements[element].isotopes) {
37
    let isotope = elements[element].isotopes[key];
38
    if (isotope.decay) {
39
      let ratioSum = 0;
40
      for (let decay in isotope.decay.decay_types) {
41
        ratioSum += isotope.decay.decay_types[decay].ratio;
42
        isotope.decay.decay_types[decay].reaction = generateReaction(key, decay);
43
      }
44
      let difference = 1 - ratioSum;
45
      if (Math.abs(difference) > 1e-7) {
46
        throw new Error('Ratios add up to '.concat(1 - difference, ' for ', key));
47
      }
48
    }
49
  }
50
}
51
52
function generateReaction(isotope, type) {
53
  switch (type) {
54
  case 'beta-':
55
    return calculateReaction(isotope, 1, 'e-', 1, 0);
56
  case '2beta-':
57
    return calculateReaction(isotope, 2, 'e-', 2, 0);
58
  case 'beta+':
59
    return calculateReaction(isotope, 1, 'e+', -1, 0);
60
  case '2beta+':
61
    return calculateReaction(isotope, 2, 'e+', -2, 0);
62
  case 'electron_capture':
63
    return calculateReaction(isotope, 1, null, -1, 0);
64
  case 'alpha':
65
    return calculateReaction(isotope, 1, 'He2+', -2, -4);
66
  case 'SF':
67
    return calculateSF(isotope);
68
  default:
69
    throw new Error('Unrecognized decay type: ' + type);
70
  }
71
}
72
73
function calculateReaction(isotope, number, particle, protonDifference, isotopeDifference) {
74
  let element = isotope.replace(/^[0-9]*/, '');
75
  let elementNumber = elements[element].number - 1;
76
  let listElements = Object.keys(elements);
77
  let otherElement = listElements[elementNumber + protonDifference];
78
79
  let isotopeNumber = Number(isotope.replace(element, '')) + isotopeDifference;
80
  let product = isotopeNumber + otherElement;
81
82
  // We need all this convoluted logic to work around missing isotopes in the data set
83
  // essentially we look for the closest isotope to the target one, and consume/produce
84
  // free neutrons in the process
85
  let distance = 0;
86
  if (!resources[product]) {
87
    let candidate = null;
88
    // first we start looking for lighter isotopes
89
    for (let otherNumber = isotopeNumber; otherNumber > 0; otherNumber--) {
90
      let otherProduct = otherNumber + otherElement;
91
      if (resources[otherProduct]) {
92
        candidate = otherProduct;
93
        distance = isotopeNumber - otherNumber;
94
        break;
95
      }
96
    }
97
    // pay attention to the upper bound. 300 is bigger than any known isotope, so it is safe
98
    for (let otherNumber = isotopeNumber; otherNumber < 300; otherNumber++) {
99
      let otherProduct = otherNumber + otherElement;
100
      if (resources[otherProduct]) {
101
        // we only replace the candidate if the distance is smaller
102
        if (isotopeNumber - otherNumber < Math.abs(distance)) {
103
          candidate = otherProduct;
104
          distance = isotopeNumber - otherNumber;
105
        }
106
        break;
107
      }
108
    }
109
    if (!candidate) {
110
      throw new Error('No candidate found for ' + isotope + ' replacing the missing isotope ' + product);
111
    }
112
    product = candidate;
113
  }
114
  let energy = resources[isotope].energy - resources[product].energy;
115
  if (distance < 0) {
116
    energy -= resources.n.energy * distance;
117
  }
118
119
  let reaction = {};
120
  reaction.reactant = {};
121
  reaction.reactant[isotope] = number;
122
  // if the isotope is heavier, the distance is negative and we produce neutrons
123
  if (distance < 0) {
124
    reaction.reactant.n = Math.abs(distance);
125
  }
126
  reaction.product = {};
127
  reaction.product[product] = number;
128
  if (particle) {
129
    reaction.product[particle] = number;
130
  }
131
  // if the isotope is lighter, the distance is positive and we produce neutrons
132
  if (distance > 0) {
133
    reaction.product.n = distance;
134
  }
135
  reaction.product.eV = energy;
136
137
  return reaction;
138
}
139
140
function calculateSF(isotope) {
141
  let breakdown = getAtomBreakdown(isotope);
142
  let halfNeutron = Math.floor(breakdown.n / 2);
143
  let halfAtom = Math.floor(breakdown.atom / 2);
144
  let firstHalf;
145
  for (let i = halfNeutron; i > 0; i--) {
146
    if (isotopeMatrix[halfAtom][i]) {
147
      firstHalf = isotopeMatrix[halfAtom][i];
148
      break;
149
    }
150
  }
151
  let secondHalfNeutron = breakdown.n - halfNeutron;
152
  let secondHalfAtom = breakdown.atom - halfAtom;
153
154
  let secondHalf;
155
  for (let i = secondHalfNeutron; i > 0; i--) {
156
    if (isotopeMatrix[secondHalfAtom][i]) {
157
      secondHalf = isotopeMatrix[secondHalfAtom][i];
158
      break;
159
    }
160
  }
161
  let firstHalfBreakdown = getAtomBreakdown(firstHalf);
0 ignored issues
show
Bug introduced by
The variable firstHalf seems to not be initialized for all possible execution paths. Are you sure getAtomBreakdown handles undefined variables?
Loading history...
162
  let secondHalfBreakdown = getAtomBreakdown(secondHalf);
0 ignored issues
show
Bug introduced by
The variable secondHalf seems to not be initialized for all possible execution paths. Are you sure getAtomBreakdown handles undefined variables?
Loading history...
163
  let neutronExcess = breakdown.n - firstHalfBreakdown.n - secondHalfBreakdown.n;
164
165
  let energy = resources[isotope].energy - resources[firstHalf].energy -
166
    resources[secondHalf].energy - resources.n.energy * neutronExcess;
167
168
  let reaction = {};
169
  reaction.reactant = {};
170
  reaction.reactant[isotope] = 1;
171
  reaction.product = {};
172
  reaction.product[firstHalf] = 1;
173
  reaction.product[secondHalf] = reaction.product[secondHalf]+1 || 1;
174
  if (neutronExcess > 0) {
175
    reaction.product.n = neutronExcess;
176
  }
177
  if (energy > 0) {
178
    reaction.product.eV = energy;
179
  }
180
  return reaction;
181
}
182
183
jsonfile.writeFileSync(args[0] + '/data/resources.json', resources, {
184
  spaces: 2
185
});
186
187
jsonfile.writeFileSync(args[0] + '/data/elements.json', elements, {
188
  spaces: 2
189
});
190